package net.stsmedia.roo.addon.heroku;

import java.io.InputStream;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.PathResolver;
import org.springframework.roo.project.Plugin;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.support.util.XmlElementBuilder;
import org.springframework.roo.support.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * Implementation of {@link HerokuOperations} interface.
 * 
 * @author Stefan Schmidt
 * @since 0.1
 */
@Component
@Service
public class HerokuOperationsImpl implements HerokuOperations {

	/**
	 * Get a reference to the FileManager from the underlying OSGi container.
	 * Make sure you are referencing the Roo bundle which contains this service
	 * in your add-on pom.xml.
	 * 
	 * Using the Roo file manager instead if java.io.File gives you automatic
	 * rollback in case an Exception is thrown.
	 */
	@Reference
	private FileManager fileManager;

	/**
	 * Get a reference to the ProjectOperations from the underlying OSGi
	 * container. Make sure you are referencing the Roo bundle which contains
	 * this service in your add-on pom.xml.
	 */
	@Reference
	private ProjectOperations projectOperations;

	/**
	 * Get a reference to the PathResolver from the underlying OSGi container.
	 */
	@Reference
	private PathResolver pathResolver;

	/** {@inheritDoc} */
	public boolean isHerokuSetupCommandAvailable() {
		return projectOperations.isFocusedProjectAvailable();
	}

	/** {@inheritDoc} */
	public void manageApplicationContext() {
		String appCtx = pathResolver.getFocusedIdentifier(Path.SPRING_CONFIG_ROOT,"applicationContext.xml");
		final InputStream in;
		boolean fileChanged = false;
		if (!fileManager.exists(appCtx)) {
			return;
		}
		in = fileManager.getInputStream(appCtx);
		final Document document = XmlUtils.readXml(in);

		Element root = document.getDocumentElement();
		if (XmlUtils.findFirstElement("/beans/bean[@id = 'dbUrl']", root) == null) {
			root.appendChild(new XmlElementBuilder("bean", document).addAttribute("class", "java.net.URI").addAttribute("id", "dbUrl").addChild(new XmlElementBuilder("constructor-arg", document).addAttribute("value", "${DATABASE_URL}").build()).build());
			fileChanged = true;
		}
		
		Element ds = XmlUtils.findFirstElement("/beans/bean[@id = 'dataSource']", root);
		if (ds != null) {
			Element url = XmlUtils.findFirstElement("property[@name = 'url']", ds);
			if (url != null) {
				url.setAttribute("value", "#{ 'jdbc:postgresql://' + @dbUrl.getHost() + @dbUrl.getPath() }");
			}
			Element username = XmlUtils.findFirstElement("property[@name = 'username']", ds);
			if (username != null) {
				username.setAttribute("value", "#{ @dbUrl.getUserInfo().split(':')[0] }");
			}
			Element password = XmlUtils.findFirstElement("property[@name = 'password']", ds);
			if (password != null) {
				password.setAttribute("value", "#{ @dbUrl.getUserInfo().split(':')[1] }");
			}
			if (url != null || username != null || password != null) {
				fileChanged = true;
			}
		}
		if (fileChanged) {
			fileManager.createOrUpdateTextFileIfRequired(appCtx,XmlUtils.nodeToString(document), false);
		}
	}

	public void installMavenPlugin() {
		// Stop if the plugin is already installed
		for (Plugin plugin : projectOperations.getFocusedModule().getBuildPlugins()) {
			if (plugin.getArtifactId().equals("maven-dependency-plugin")) {
				return;
			}
		}

		Element configuration = XmlUtils.getConfiguration(getClass());
		Element plugin = XmlUtils.findFirstElement("/configuration/plugin", configuration);

		// Now install the plugin itself
		if (plugin != null) {
			projectOperations.addBuildPlugin(projectOperations.getFocusedModuleName(), new Plugin(plugin));
		}
	}
	
	public void createProcfile() {
		String procfile = pathResolver.getFocusedIdentifier(Path.ROOT, "Procfile");
		if (!fileManager.exists(procfile)) {
			fileManager.createOrUpdateTextFileIfRequired(procfile, "web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war", false);
		}
	}
}
